/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.tools.idea.adblib

import com.android.adblib.AdbFeatures
import com.android.adblib.AdbSession
import com.android.adblib.ServerStatus
import com.android.tools.analytics.UsageTracker
import com.android.tools.idea.adb.AdbOptionsService
import com.android.tools.idea.isAndroidEnvironment
import com.google.wireless.android.sdk.stats.AdbServerStatus
import com.google.wireless.android.sdk.stats.AndroidStudioEvent
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.project.Project
import com.intellij.openapi.startup.ProjectActivity
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.launch

/** Retrieve status of ADB Server and upload stats */
class AdbServerStatusReporter(val statusReporter: (ServerStatus) -> Unit) : ProjectActivity {
  @Suppress("unused") constructor() : this(::reportAdbStatus)

  private val logger = thisLogger()

  override suspend fun execute(project: Project) {
    if (!isAndroidEnvironment(project)) {
      return
    }
    val session = AdbLibService.getInstance(project).session
    session.scope.launch {
      runCatching {
        retrieveServerStatus(session)?.let { serverStatus ->
          statusReporter(serverStatus)
          logger.info("ADB server logs can be found at: ${serverStatus.absoluteLogPath}")
        }
      }.onFailure { e ->
        if (e !is CancellationException) {
          thisLogger().warn("Cannot report `AdbServerStatus` due to a problem with adb server", e)
        }
      }
    }
  }

  private suspend fun retrieveServerStatus(session: AdbSession): ServerStatus? {
    return if (session.hostServices.hostFeatures().contains(AdbFeatures.SERVER_STATUS)) {
      session.hostServices.serverStatus()
    } else null
  }
}

private fun reportAdbStatus(serverStatus: ServerStatus) {
  UsageTracker.log(
    AndroidStudioEvent.newBuilder()
      .setKind(AndroidStudioEvent.EventKind.ADB_SERVER_STATUS)
      .setAdbServerStatus(
        AdbServerStatus.newBuilder()
          .setIsManaged(AdbOptionsService.getInstance().optionsUpdater.useUserManagedAdb())
          .setVersion(serverStatus.version)
          .setIsUsbBackendForced(serverStatus.usbBackendForced)
          .setUsbBackend(serverStatus.usbBackend.toProto())
          .setMdnsBackend(serverStatus.mdnsBackEnd.toProto())
          .setIsMdnsBackendForced(serverStatus.mdnsBackEndForced)
      )
  )
}

private fun ServerStatus.UsbBackend.toProto(): AdbServerStatus.USBBackend =
  when (this) {
    ServerStatus.UsbBackend.UNKNOWN -> AdbServerStatus.USBBackend.TYPE_USB_UNKNOWN
    ServerStatus.UsbBackend.LIBUSB -> AdbServerStatus.USBBackend.TYPE_LIBUSB
    ServerStatus.UsbBackend.NATIVE -> AdbServerStatus.USBBackend.TYPE_NATIVE
  }

private fun ServerStatus.MdnsBackend.toProto(): AdbServerStatus.MDNSBackend =
  when (this) {
    ServerStatus.MdnsBackend.UNKNOWN -> AdbServerStatus.MDNSBackend.TYPE_MDNS_UNKNOWN
    ServerStatus.MdnsBackend.BONJOUR -> AdbServerStatus.MDNSBackend.TYPE_BONJOUR
    ServerStatus.MdnsBackend.OPENSCREEN -> AdbServerStatus.MDNSBackend.TYPE_OPENSCREEN
  }
